package edu.neu.cs6515.net;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.JAXBException;

import com.google.java.contract.Ensures;
import com.google.java.contract.Requires;

import edu.neu.cs6515.admin.Administrator;
import edu.neu.cs6515.board.HexagonBoard;
import edu.neu.cs6515.turn.AbstractTurnProxy;
import edu.neu.cs6515.turn.ITurnProxy;
import edu.neu.cs6515.xml.False;
import edu.neu.cs6515.xml.Placement;
import edu.neu.cs6515.xml.Score;
import edu.neu.cs6515.xml.Tile;
import edu.neu.cs6515.xml.w12.ReRackPlease;
import edu.neu.cs6515.xml.w12.Rerack;
import edu.neu.cs6515.xml.w12.Rerackable;
import edu.neu.cs6515.xml.w12.True;

/**
 * class serve as a proxy to a remote TurnProxy
 */
public class ProxyOfTurnProxy extends AbstractTurnProxy {

    private final IProxyInOutput inOut;

    /**
     * C'tor
     * 
     * @param board
     *            current state of a board
     * @param tilesInPlayersHand
     *            tiles available
     * @param score
     *            current score
     * @param inOut
     *            input output broker
     */
    public ProxyOfTurnProxy(final HexagonBoard board,
            final List<Tile> tilesInPlayersHand,
            final Score score,
            final IProxyInOutput inOut) {
        super(board, tilesInPlayersHand, score);
        this.inOut = inOut;
    }

    @Override
    protected List<Tile> getNewTile() {
        Placement p = this.getPlacementsInThisTurn().get((this.getPlacementsInThisTurn().size() - 1));
        List<Tile> tileToReturn = new LinkedList<Tile>();
        try {
            inOut.respond(p);
            Object obj = inOut.receive();
            System.out.println(obj);
            if (obj instanceof Tile) {
                tileToReturn.add((Tile) obj);
                this.tilesInPlayersHand.add((Tile) obj);
            }
            return tileToReturn;
        } catch (InputOutputException e) {
            e.printStackTrace();
            return tileToReturn;
        }
    }

    @Override
    public boolean isReRackable() {
        if (this.isReRacked() ||
                    isAnyLowestScoredColorInHand() ||
                    this.getRequiredPlacements() > 0 ||
                    this.getAllTilesInPlayersHand().size() < Administrator.INITIAL_TILES_IN_HAND) {
            return false;
        } else {
            try {
                inOut.respond(new Rerackable());
                Object obj = inOut.receive();
                System.out.println(obj);
                return (obj instanceof True);
            } catch (InputOutputException e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    @Requires({ "isReRackable()" })
    @Override
    public void reRack() {
        try {
            inOut.respond(new Rerack());
            Object obj = inOut.receive();
            System.out.println(obj);
            this.tilesInPlayersHand.removeAll(this.tilesInPlayersHand);
            this.tilesInPlayersHand.addAll(((Rerack) obj).getTile());
            this.reRacked = true;
        } catch (InputOutputException e) {
            e.printStackTrace();
        }
    }
}
